MATLAB을 이용해 데이터 분석을 수행하다보면 문자 데이터를 다룰 필요가 생긴다. 가령, 파일을 불러올 때의 파일 경로나, plot 창의 x, y 축 라벨을 적어주는 경우, 혹은 데이터 자체가 문자인 경우도 있다. 이번 시간에는 MATLAB에서 문자 데이터를 다루는 법에 대해 알아보고자 한다.

MATLAB의 문자 데이터: character, string

MATLAB은 두 가지 타입의 데이터 형식으로 문자 데이터를 다룬다. 하나는 character(char형)이고 다른 하나는 string(string형)이다. string형은 R2016b 버전부터 도입된 데이터 타입이고, char형은 가지고 있지 않는 여러 기능들을 기본 탑재하고 있다. 여기서 말하는 “여러 기능”은 가령 “모두 소문자로 바꾸기”, “특정 문자만 제거하기” 등과 같은 기능이다. 사실상 string형이 char형의 거의 완벽한 상위호환이라고 말 할 수 있다.

두 변수 타입에 대한 차이를 하나 하나 비교해가면서 두 변수 타입이 어떤 것인지 알아보도록 하자.

아이콘 형태 차이

char형과 string형은 아이콘 모양에서부터 차이를 보인다. 아래 그림에서 왼쪽에 char형, 오른쪽이 string형이다.


변수 선언 방법의 차이

두 데이터 타입은 변수를 선언하는 방법에서 차이를 보인다. char형은 작은따옴표(‘ ‘) 안에 문자를 집어넣어 변수를 선언하고, string형은 큰따옴표(“ “) 안에 문자를 집어 넣어 변수를 선언한다.

char_type = 'abc';
string_type = "abc";

class(char_type)
class(string_type)
ans =

    'char'


ans =

    'string'

벡터의 관점에서 본 원소 개수로써의 차이

char형은 작은따옴표 안에 들어가는 글자 하나 벡터 하나의 원소에 대응시킨 것인 반면 string형은 큰따옴표 안에 들어가는 글자 전체가 하나의 벡터 원소이다. 이를 확인하기 위해서 “size” 함수를 이용할 수 있다.

char_type = 'abc';
string_type = "abc";

size(char_type)
size(string_type)
ans =

     1     3


ans =

     1     1

아래 그림을 이용해 말하자면, 각각의 네모가 하나의 벡터 원소라고 했을 때 char형은 벡터 원소들 하나 하나에 글자 하나씩 끼워 맞춰져 있지만 string 형은 큰따옴표 안에 들어가는 모든 글자를 하나의 벡터 원소에 집어 넣은 형태이다.


따라서, char형은 글자 하나 하나를 분석할 때 유용할 수 있다. 왜냐하면 글자의 순번에 맞춰 글자를 빼내거나 집어넣기에 편하기 때문이다. 아래의 예시를 살펴보자.

my_char = 'Hello World!';
my_char(1:5)
ans =

    'Hello'
my_char = 'Hello World!';
my_char(end) = '?'
ans =
my_char =

    'Hello World?'

반면에 string형은 여러 문자열들을 다룰 때 편리할 수 있다. 큰따옴표 안에 넣는 각각의 문자열 덩어리가 하나의 벡터 원소로 인식되기 때문이다. 방대한 텍스트를 분석할 때는 수많은 단어들을 한꺼번에 다루어야 하므로 string형 데이터를 이용하면 분석이 더 용이해질 수 있을 것이다.

SC = ["My", "life", "for", "Aiur"]
SC(1:2)
SC = 

  1×4 string array

    "My"    "life"    "for"    "Aiur"


ans = 

  1×2 string array

    "My"    "life"

char형이 문자를 표현하는 방법

char형 문자들이 벡터 하나 하나의 원소로 작용하는 것은 마치 숫자가 벡터 원소로 들어가있는 것과 같은 인상을 준다. 실제로 char형 데이터를 숫자로 변환해보면 특정 숫자 배열이 출력되는 것을 알 수 있다. 다시 말해, char형은 메모리 상에서는 실제로 숫자의 나열이고, 우리가 보는 MATLAB에서 보여지기로 문자로 보여지는 방식을 따르는 것이다. 가령 아래와 같이 커맨드 윈도우에 입력해보자.

double('MATLAB')
ans =

    77    65    84    76    65    66

이 번호는 유니코드 UTF-16 인코딩 코드표에서 약속한 것을 따르는 것이다. 가령 77은 ‘M’, 65는 ‘A’로 약속되어 있다. “유니코드”라는 말이 어렵게 느껴질 수도 있는데, “유니코드”는 이런 저런 문자열 인코딩 체계를 한 곳에 몰아 넣어서 만든 인코딩 체계라고 할 수 있는 것이다. UTF-16의 첫번째 128개의 코드표는 ASCII 코드표에서 가져왔다. 전체 UTF-16 코드표는 여기에서 확인할 수 있다.

그래서 이것을 역으로 잘 활용하면 UTF-16 코드표에 있는 특수 문자를 써먹을 수도 있다. 176번은 온도 표시(“° “)를 지칭한다.

['The temperature is 18', char([176]),'C']
ans =

    'The temperature is 18°C'

변수가 차지하는 메모리 용량의 차이

char형 변수는 글자 하나 당 메모리 용량 2 byte를 차지하지만, string형 변수는 기본이 150 byte를 차지하는 것으로 보인다. 글자가 늘어날 수록 string 변수가 차지하는 메모리 용량은 커진다. 이것을 확인하기 위해서 “whos” 명령어를 이용할 수 있다.

char_type = 'abc';
string_type = "abc";
whos
  Name             Size            Bytes  Class     Attributes

  char_type        1x3                 6  char                
  string_type      1x1               150  string   

공개된 documentation에는 string형이 메모리 용량을 차지하는 원리에 대해 설명하지 않아 정확히 알 수는 없지만, 이러한 결과가 시사하는 바는 string형은 글자에 대한 정보 뿐만 아니라 다른 내장 함수들에 관한 정보가 더 포함되어 있다는 것을 말해준다.

문자열의 길이 측정하기

char형 변수는 벡터의 원소 하나 하나를 글자로 인식하기 때문에 벡터/행렬에서 사용하는 “size”나 “length” 함수를 그대로 사용하면 된다. 반면에 string형 변수는 큰 따옴표 안에 들어가는 글자 전체가 하나의 원소이기 때문에 문자열의 길이를 재는 strlength 함수를 사용해야 한다.

char_type = 'abc';
string_type = "abc";
length(char_type)
strlength(string_type)

ans =

     3


ans =

     3

두 문자열 합치기

char형 변수 두 개를 합치기 위해선 벡터 두 개를 합치는 것과 동일한 방법을 사용하면 된다. 즉, 아래와 같이 대괄호를 이용해 두 벡터를 합치듯이 두 char형 변수를 합칠 수 있다.

char1 = 'abc';
char2 = 'def';
char3 = [char1, char2]
char3 =

    'abcdef'

string형 변수의 두 문자열을 합치기 위해선 “+” 연산자를 사용하거나 append 연산자를 사용하면 된다.

str1 = "abc";
str2 = "def";
str3 = str1 + str2
str4 = append(str1, str2) % 혹은 str1.append(str2)
str3 = 

    "abcdef"


str4 = 

    "abcdef"

중괄호{ }를 이용해 string형 내의 문자에 엑세스하기

char형을 다루면서 char형은 문자 각각이 벡터 원소로 인식되기 때문에 char형을 이용하면 하나 하나의 문자를 다루기 좋다고 언급한 바 있다. 따라서, string 형으로 여러 문자열들을 다루다가 문자 하나씩 다룰 필요가 있을 때는 임시로 string형 문자열을 char형으로 바꾸어 각 문자별 작업을 수행해줄 수 있다. 가령 아래와 같은 예시를 생각해볼 수 있다.

str_vec = ["오늘은", "하루는", "바쁜 하루였다"];
temp_char = char(str_vec(1));
temp_char(3) = [];
str_vec(1) = string(temp_char);
str_vec
str_vec = 

  1×3 string array

    "오늘"    "하루는"    "바쁜 하루였다"

그러나 중괄호{ }를 이용해 indexing 해주면 string형이 아닌 char형으로 바로 반환 받게 되어서 char형으로 바꾸고 다시 string형 배열에 넣어주는 번거로움을 덜수있다.

str_vec = ["오늘은", "하루는", "바쁜 하루였다"];
str_vec{1}(3) = [];
str_vec
str_vec = 

  1×3 string array

    "오늘"    "하루는"    "바쁜 하루였다"

string형 변수만 쓸 수 있는 함수

위의 내용까지만 보면 굳이 string형을 쓸 필요가 있을까 싶기도 하지만 이제부터 소개하는 함수들을 보면 편리함을 느낄 수 있을 것이다. 아래에서 소개하는 함수들은 유용하다고 생각하는 대표적인 함수들만 몇 가지 추린 것이다. 만약 전체 리스트가 궁금하다면 Command Window에서 “edit string”이라고 치면 string형 변수에 특화된 함수 목록을 확인해볼 수 있다.

contains

string형 벡터/행렬 안에 특정 단어나 패턴이 포함되어 있는지 검사해준다.

my_words = ["How", "Are", "You", "?"; "Are", "You", "Okay", "?"]
contains(my_words, "You")
my_words = 

  2×4 string array

    "How"    "Are"    "You"     "?"
    "Are"    "You"    "Okay"    "?"
ans =

  2×4 logical array

   0   0   1   0
   0   1   0   0

위 예시에서는 “my_words”라는 string형 배열에 “You” 라는 글자가 들어가있는지를 검사해주었다. 만약, 여러 단어를 한꺼번에 검사하고 싶다면 아래와 같이 수행할 수도 있다.

contains(my_words, ["You", "?"])
ans =

  2×4 logical array

   0   0   1   1
   0   1   0   1

R2020b 버전부터는 “pattern”의 개념이 도입되어 “contains” 함수를 같이 활용하면 string형 배열에 특정 패턴이 포함되어 있는지 알 수 있다. 아래의 예시에서는 R, 숫자 네 개, 글자 하나의 패턴을 가진 string 원소가 “str_vec” 벡터에 포함되어 있는지 찾아주는 예시이다.

str_vec = ["안녕하세요?", "현재 최신 MATLAB 버전은 R2022b 입니다"];
pat = "R"+digitsPattern(4)+lettersPattern(1);
contains(str_vec, pat)
ans =

  1×2 logical array

   0   1

digitsPattern, lettersPattern 외에 더 다양한 패턴에 대해 알고 싶다면 여기에서 확인해보도록 하자.

count

string형 배열의 원소들 중 특정 단어나 패턴이 몇 번이나 나타나는지 분석해준다. 아래는 특정 단어가 몇 번이나 들어갔는지 카운트 해주는 예시이다.

str_vec = ["빨강 빨강 파랑 파랑 파랑 초록", "빨강 파랑 파랑 파랑 초록 초록 초록"];
count(str_vec, "초록")
ans =

     1     3

아래는 글자 하나에 숫자 하나가 오는 패턴이 몇 번이나 들어가있는지 카운트 해주는 예시이다.

str_vec = ["안녕하세요?", "현재 최신 MATLAB 버전은 R2022b 입니다"];
pat = lettersPattern(1) + digitsPattern(1);
count(str_vec, pat)
ans =

     0    1

startsWith

string형 배열의 원소들이 특정 단어나 패턴으로 시작하는지 점검해준다.아래는 특정 단어로 시작하는지 점검하는 예시이다.

str_vec = ["my_file.mat", "my_documentation.doc", "my_final_ppt.pptx", "my_list.mat", "my_dataset.7z"];
startsWith(str_vec, "my_")
ans =

  1×5 logical array

   1   1   1   1   1

마찬가지로 패턴도 사용할 수 있다. 아래 예시에서는 두 글자 다음에 언더바 그리고 글자 패턴이 온 뒤 또 언더바가 오는 방식으로 문자열이 시작하는지 점검한 예시이다.

str_vec = ["my_file.mat", "my_documentation.doc", "my_final_ppt.pptx", "my_list.mat", "my_dataset.7z"];
pat = lettersPattern(2)+"_"+lettersPattern+"_";
startsWith(str_vec, pat)
ans =

  1×5 logical array

   0   0   1   0   0

endsWith

string형 배열의 원소들이 특정 단어나 패턴으로 끝나는지 점검해준다. 아래는 특정 단어로 끝나는지 점검하는 예시이다.

str_vec = ["my_file.mat", "my_documentation.doc", "my_final_ppt.pptx", "my_list.mat", "my_dataset.7z"];
endsWith(str_vec, ".mat")
ans =

  1×5 logical array

   1   0   0   1   0

마찬가지로 패턴도 사용할 수 있다. 아래 예시에서는 두 글자 다음에 언더바 그리고 글자 패턴이 온 뒤 또 언더바가 오는 방식으로 문자열이 시작하는지 점검한 예시이다.

str_vec = ["my_file.mat", "my_documentation.doc", "my_final_ppt.pptx", "my_list.mat", "my_dataset.7z"];
pat = "_"+lettersPattern+"."+lettersPattern;
endsWith(str_vec, pat)
ans =

  1×5 logical array

   1   1   1   1   0

erase

string형 배열의 원소들 중 특정 글자를 지우거나 특정 패턴을 만족하는 글자를 지워준다.

str_vec = ["my_file.mat", "my_documentation.doc", "my_final_ppt.pptx", "my_list.mat", "my_dataset.7z"];
erase(str_vec, "my_")
ans = 

  1×5 string array

    "file.mat"    "documentation.doc"    "final_ppt.pptx"    "list.mat"    "dataset.7z"

역시 마찬가지로 패턴을 사용할 수도 있다. 아래의 예시에선 파일의 확장자를 모두 지우는 예시이다. 여기서 “alphanumericsPattern”은 문자나 숫자로 구성된 패턴을 의미한다.

str_vec = ["my_file.mat", "my_documentation.doc", "my_final_ppt.pptx", "my_list.mat", "my_dataset.7z"];
pat = "."+alphanumericsPattern;
erase(str_vec, pat)
ans = 

  1×5 string array

    "my_file"    "my_documentation"    "my_final_ppt"    "my_list"    "my_dataset"

extractAfter

string형 배열의 원소들에 대해 특정 글자 이후의 문자들을 추출해내는 기능이다. 이게 무슨 쓸모가 있나 싶겠지만 전체 파일 경로에서 파일명을 추출해낼 때 유용할 수 있다. 아래의 예시는 패턴을 이용하기 때문에 R2020b 이상에서만 적용된다는 점을 명심하자. 여기서 wildcardPattern은 몇 개의 글자 혹은 숫자가 포함된 패턴을 의미하고 asManyOfPattern은 입력된 패턴을 최대한 여러번 사용하도록 지시하는 것이다.

str_vec = ["C:\Workspace\hahaha.pdf", "C:\temp\myfolder\myfolder2\hohoho.txt"];
pat = asManyOfPattern(wildcardPattern + "\");
extractAfter(str_vec, pat)
ans = 

  1×2 string array

    "hahaha.pdf"    "hohoho.txt"

split

공란(space) 혹은 특정 문자열을 이용해 문자열을 구분하여 분할하는 기능이다. 가령, 책의 텍스트를 모두 얻어내서 어절 단위로 나누어 분석하고 싶다면 아주 유용할 수 있는 기능이다.

str_vec = "오늘은 너무 늦었으니까 일찍 자야겠다";
split(str_vec)
ans = 

  5×1 string array

    "오늘은"
    "너무"
    "늦었으니까"
    "일찍"
    "자야겠다"

공란이 아닌 다른 문자로 문자열을 구분하도록 설정할 수도 있다.

str_vec = "C:\my_folder\my_folder2\my_file.txt";
split(str_vec, "\")
ans = 

  4×1 string array

    "C:"
    "my_folder"
    "my_folder2"
    "my_file.txt"

cellstr

char형 문자열은 각각의 문자가 하나의 벡터 원소로 인식 되기 때문에 여러 문자열을 한번에 다루기 위해선 cell 배열을 사용한다. “cellstr” 함수는 string형을 이용해 만든 여러 문자열들을 cell 배열에 담긴 char형 문자열로 변환해주는 기능이다.

str_vec = ["어제는", "바쁜", "하루였다."]
C = cellstr(str_vec)
str_vec = 

  1×3 string array

    "어제는"    "바쁜"    "하루였다."


C =

  1×3 cell array

    {'어제는'}    {'바쁜'}    {'하루였다.'}